/**
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

package pittypat.web;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import pittypat.IJson;
import pittypat.IUser;
import pittypat.Json;
import pittypat.User;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 提供与响应相关的一组辅助方法。
 */
final class ResponseHelper {
	private static final Logger LOGGER = LogManager.getLogger(ResponseHelper.class);

	/**
	 * 发送错误文本消息。
	 * 
	 * @param response
	 *            目标响应对象。
	 * @param message
	 *            要发送的错误消息。
	 */
	public static void sendErrorMessage(HttpServletResponse response, String message) {
		// 默认总是认为向客户端发送 json 数据
		response.setContentType("application/json;charset=UTF-8");
		response.setCharacterEncoding("utf-8");

		try {
			PrintWriter writer = response.getWriter();

			writer.write("{\"type\":\"error\",\"message\":\"");
			writer.write(message == null ? "" : Json.escape(message));
			writer.write("\"}");

			response.setStatus(200);
		} catch (IOException e) {
			LOGGER.fatal(e.getMessage(), e);
		}
	}

	/**
	 * 发送异常。如果当前系统处在调试模式下，则发送完整的堆栈跟踪信息。
	 * 
	 * @param response
	 *            目标响应对象。
	 * @param exception
	 *            要发送的异常对象。如果为 null，什么都不做。
	 * @param isDebug
	 *            指示当前系统是否处在调试模式下。
	 */
	public static void sendErrorMessage(HttpServletResponse response, Throwable exception, boolean isDebug) {
		if (exception == null) {
			return;
		}

		try {
			String msg = "";

			if (isDebug) {
				// 获取堆栈跟踪信息字符串
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				PrintWriter writer = new PrintWriter(stream);
				exception.printStackTrace(writer);
				writer.flush();

				// 要发送的消息
				msg = stream.toString();

				// 关闭辅助流
				writer.close();
				stream.close();
			} else {
				// 非调试模式下，仅仅发送异常的 Message
				msg = exception.getLocalizedMessage();
			}

			// 使用错误消息发送方法发送消息
			sendErrorMessage(response, msg);
		} catch (IOException e) {
			LOGGER.fatal(e.getMessage(), e);
		}
	}

	/**
	 * 发送一个 IJson 值。VirtualFile 和 ByteArray 发送文件，其他则序列化为 JSON 字符串发送到客户端。
	 * 
	 * @param response
	 *            目标响应对象。
	 * @param value
	 *            要发送的值。
	 * @throws IOException
	 */
	public static void sendValueMessage(HttpServletResponse response, IJson value) throws IOException {
		// 默认总是认为向客户端发送 json 数据
		response.setContentType("application/json;charset=UTF-8");
		response.setCharacterEncoding("utf-8");

		if (value == null) {
			// 目标功能方法没有返回值，向客户端响应一个空消息
			response.getWriter().write("{\"type\":\"empty\"}");
		} else {
			if (value instanceof VirtualFile) {
				// 向客户端发送由一个虚拟路径表示的文件内容
				try {
					((VirtualFile) value).send(response);
				} catch (FileNotFoundException e) {
					response.sendError(404, "Not Found");
				}
			} else if (value instanceof ByteArray) {
				// 向客户端发送一个二进制数组
				((ByteArray) value).send(response);
			} else {
				// 发送 json 对象。
				PrintWriter writer = response.getWriter();

				writer.write("{\"type\":\"value\",\"valueType\":\"" + Json.getTypeName(value) + "\",\"value\":");

				value.write(writer);

				writer.write('}');
			}
		}

		response.setStatus(200);
	}

	/**
	 * 发送一个 IUser 值。
	 * 
	 * @param response
	 *            目标响应对象。
	 * @param user
	 *            要发送的用户信息。
	 * @throws IOException
	 */
	public static void sendUserMessage(HttpServletResponse response, IUser user) throws IOException {
		// 默认总是认为向客户端发送 json 数据
		response.setContentType("application/json;charset=UTF-8");
		response.setCharacterEncoding("utf-8");

		if (user == null) {
			user = User.ANONYMOUS;
		}

		PrintWriter writer = response.getWriter();

		writer.write("{\"type\":\"user\",\"info\":");
		user.write(writer);
		writer.write('}');

		response.setStatus(200);
	}
}
